package main

import (
	"encoding/json"
	"fmt"
)

// go 没有面向对象，所以对于对象型数据采用结构体表示

type Book struct { // Book首字母大写相当于public ，如果小写book则表示private只能本包中访问, Book内的字段也一样遵循这个原则，private权限下，json包也不能获取到
	Title  string  `json:"name,omitempty"` // 结构体tag，指定该字段在json包中名称为name，相当于一个别名, 序列化时显示为name，如果为空则忽略
	author string  `json:"-"`              // json包中忽略该字段, 此处author为首字母小写，所以这个json tag没啥用，因为private不对外暴漏
	Price  float32 `json:"-,"`             // json包中序列化后该字段为 -
	Id     int64   `json:"bookId"`         // 结构体tag，指定该字段在json包中名称为bookId，相当于一个别名
	int8           // 匿名字段，结构体内字段名称唯一，所以匿名字段类型必须唯一，不能已经存在
}

func changePrice(b Book, p float32) {
	b.Price = p
}

func changePrice2(b *Book, p float32) {
	b.Price = p
}

type Food interface { // 接口定义，go中定义接口不需要显示继承，采用隐式继承，只要实现了接口方法就是继承
	name() string
}

type Banana struct {
	small, color string // 定义两个属性颜色和味道
}

func (b Banana) name() string { // 这就算实现了Food的方法
	return "banana"
}

type Cuke struct {
	color string
}

func (c *Cuke) name() string {
	return "cuke"
}

type MyString string // 这种相当于定义了一个别名，一般用于const声明常量时使用

const (
	M1 MyString = "abc" // 常量
)

type Apple struct {
	Banana // 匿名变量，此时相当于将匿名变量类型的字段融合到了当前对象，可以直接通过Apple实例 直接访问使用，比如：appleVar.color
	price  float32
}

func main() {
	// 注意，里面要用双引号设置值
	// 简写变量创建
	book0 := Book{}
	book1 := Book{"java", "tom", 11.1, 100, 0}      // 结构体声明初始化 方式1
	book2 := Book{Title: "c", Price: 14.0, int8: 0} // 声明初始化方式2
	// book1和book2简写声明方式等价于下面这种先声明后初始化方式
	var book3 Book                     // 声明
	book3 = Book{"go", "tom", 1, 1, 0} // 初始化

	// 通过new初始化形式创建，b4是新创建对象的引用(指针)
	var b4 *Book = new(Book)
	// 简写new初始化形式
	b5 := new(Book)

	// &形式的创建对象方式 等于 new形式的创建对象， 这两种方式创建的对象不需要事先字段赋值，相当于空构造函数
	var b6 *Book = &Book{} //
	// 简写形式
	b7 := &Book{}
	b7.author = "abc" // (*struct_name).field_name == struct_name.field_name  通过 . 访问变量两种形式等效
	(*b7).Price = 10  //

	// 通过new 或者 & 创建的对象在使用或者传递时，是指针对象传递和使用都会影响原值，而通过type_name{}形式创建的是值对象，传递和使用都是实际值，不会影响原值
	changePrice(book0, 222)
	changePrice(*b4, 222)

	changePrice2(&book0, 222)
	changePrice2(b4, 222)

	// println不支持打印对象, fmt可以
	fmt.Println(book0)
	fmt.Println(book1)
	fmt.Println(book2)
	fmt.Println(book3)
	fmt.Println("==========================")
	// 通过 new 或者 &创建的对象打印出来前面带个&
	fmt.Println(b4)
	fmt.Println(b5)
	fmt.Println(b6)
	fmt.Println(b7)

	jsonByte, err := json.Marshal(book1)
	fmt.Println(jsonByte, string(jsonByte), err)

	fmt.Println("==========================")

	ba := Banana{"1", "yellow"}
	fmt.Println(ba.name(), (&ba).name()) // 一样？？？
	ck := Cuke{"green"}
	fmt.Println(ck.name(), (&ck).name())

	fmt.Println(M1)

	ap := Apple{Banana{"1", "red"}, 3}
	fmt.Println(ap.color, ap.small) //
}
